#pragma once
#include "CGALDefinition.h"
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <CGAL/Cartesian_converter.h>

#ifdef MYLIB_API_EXPORT
#define MYLIB_API __declspec(dllexport)
#else
#define MYLIB_API __declspec(dllimport)
#endif

template <class BuildKernel, class InputKernel, class MYHDS>//...no saying
class CKernelRebuilder : public CGAL::Modifier_base<MYHDS>
{
private:
	typedef CGAL::Polyhedron_3<BuildKernel, My_items> BuildPolyType;
	typedef CGAL::Polyhedron_3<InputKernel, My_items> InputPolyType;

	typedef typename BuildPolyType::HalfedgeDS HDS;
	typedef typename BuildPolyType::Point_3 Point;
	typedef CGAL::Polyhedron_incremental_builder_3<HDS> Builder;
	
	//kernel converter
	typedef CGAL::Cartesian_converter<InputKernel, BuildKernel> Converter;

private:
	InputPolyType* Input_poly;

public:
	CKernelRebuilder(){Input_poly = NULL;}
	CKernelRebuilder(InputPolyType* poly)
	{
		if (!poly && poly->is_valid())
		{
			Input_poly = poly;
		}
		else
			Input_poly = NULL;
	}

	~CKernelRebuilder() {}
	//function object
	void operator()(HDS& hds)
	{
		Builder builder(hds,true);
		builder.begin_surface(3,1,6);
		if (!add_vertices(builder))
		{
			return;
		}
		if (!add_facets(builder))
		{
			return;
		}
		//
		if ( builder.check_unconnected_vertices()) 
		{
			if (!builder.remove_unconnected_vertices())
			{
				return;
			}
		}
		//
		builder.end_surface();
	}

private:
	//
	bool add_vertices(Builder &builder)
	{
		if (!Input_poly)
		{
			return false;
		}
		//iterate all the points, convert and add
		typedef typename InputPolyType::Point_iterator My_Pt_itr;
		typedef typename InputPolyType::Point_3 My_Point;
		//
		Converter Myconv;
		//
		My_Pt_itr pt_itr = Input_poly->points_begin();
		for (;pt_itr != Input_poly->points_end(); pt_itr++)
		{
			My_Point pt = *pt_itr;
			//kernel convert
			Point newpt= Myconv(pt);
			//
			builder.add_vertex(newpt);
		}
		//
		return true;
	}
	//
	bool add_facets(Builder &builder)
	{
		if (!Input_poly)
		{
			return false;
		}
		//iterate all the facets, convert and add
		typedef InputPolyType::Facet_iterator My_facet_itr;
		typedef InputPolyType::Facet My_Facet;

		typedef BuildPolyType::Halfedge_handle HE_itr;
		//
		My_facet_itr fc_itr = Input_poly->facets_begin();
		for (;fc_itr != Input_poly->facets_end(); fc_itr++)
		{
			My_Facet fc = *fc_itr;
			//get vertex indices
			InputPolyType::Halfedge_around_facet_circulator hitr = fc.facet_begin();
			CGAL_assertion(CGAL::circulator_size(hitr) == 3 );//triangle
			//
			std::vector<std::size_t> vts;
			vts.push_back(std::size_t(std::distance(Input_poly->vertices_begin(),hitr->vertex())));
			++hitr;
			vts.push_back(std::size_t(std::distance(Input_poly->vertices_begin(),hitr->vertex())));
			++hitr;
			vts.push_back(std::size_t(std::distance(Input_poly->vertices_begin(),hitr->vertex())));
			//
			HE_itr hf = builder.add_facet(vts.begin(),vts.end());
			//mtl
			hf->facet()->mtl = fc.mtl;
		}
		//
		return true;
	}
};

//conversion between Poly_IK and Poly_EK
class MYLIB_API CKernelConverter
{
private:
	typedef Polyhedron_3 IK_Poly_3;

protected:
	static std::auto_ptr<CKernelConverter> _instance;

public:
	//the output should be created before calling this func
	bool IK_to_EK(IK_Poly_3* input, EK_Poly_3* output);
	//the output should be created before calling this func
	bool EK_to_IK(EK_Poly_3* input, IK_Poly_3* output);

public:
	CKernelConverter(void);
	~CKernelConverter(void);

	static CKernelConverter* GetSingleton()
	{
		if (NULL == _instance.get())
		{
			_instance.reset(new CKernelConverter);
		}
		return _instance.get();
	}
};



